import Flutter
import UIKit
import TXLoginoauthSDK
import SnapKit
import YYText
import SafariServices

public class TverifyPlugin: NSObject, FlutterPlugin {
    private var channel: FlutterMethodChannel! = nil
    
    fileprivate static var root: FlutterViewController! {
        get {
            UIApplication.shared.delegate?.window!!.rootViewController! as? FlutterViewController
        }
    }
    
    public static func register(with registrar: FlutterPluginRegistrar) {
        let channel = FlutterMethodChannel(name: "tverify", binaryMessenger: registrar.messenger())
        let instance = TverifyPlugin()
        instance.channel = channel
        registrar.addMethodCallDelegate(instance, channel: channel)
    }
    
    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        let arguments = call.arguments as? [String: Any] ?? [:]
        switch call.method {
        case "initLogin":
            initLogin(result, arguments: arguments)
        case "preLogin":
            preLogin(result)
        case "login":
            login(result, arguments: arguments)
        case "getSimInfo":
            getSimInfo(result)
        case "deleteScrip":
            deleteScrip(result)
        case "setTimeout":
            setTimeout(result, arguments: arguments)
        case "dismissLogin":
            dismissLogin(result, arguments: arguments)
        default:
            result(FlutterMethodNotImplemented)
        }
    }
    
    func onClickListener(id: String) {
        channel.invokeMethod("onClickListener", arguments: ["id": id])
    }
    
    private func initLogin(_ result: @escaping FlutterResult, arguments: [String: Any]) {
        TXLoginOauthSDK.initLogin(withId: arguments["appId"] as! String)
        result(nil)
    }
    
    private func preLogin(_ result: @escaping FlutterResult) {
        TXLoginOauthSDK.preLogin { results in
            result(results)
        } fail: { error in
            let details = error as! [String: Any]
            let code = details["preResultCode"] as! String
            let message = details["resultMsg"] as! String?
            result(FlutterError(code: code, message: message, details: error))
        }
    }
    
    private func login(_ result: @escaping FlutterResult, arguments: [String: Any]) {
        let model: TXLoginUIModel = .init(arguments, plugin: self)
        PrivacyDialog.instance.model = model
        PrivacyDialog.instance.checked = model.privacyState
        PrivacyDialog.instance.loginEvent = nil
        TXLoginOauthSDK.setLoginDelegate(TverifyPlugin.root!)
        TXLoginOauthSDK.login(with: TverifyPlugin.root!, andUIModel: model) { results in
            if results["loginResultCode"] as! String? != "200087" {
                result(results)
            }
        } fail: { error in
            let details = error as! [String: Any]
            let code = details["loginResultCode"] as! String
            let message = details["resultMsg"] as! String?
            result(FlutterError(code: code, message: message, details: error))
        }
    }
    
    private func getSimInfo(_ result: @escaping FlutterResult) {
        result(TXLoginOauthSDK.getSimInfo())
    }
    
    private func deleteScrip(_ result: @escaping FlutterResult) {
        result(TXLoginOauthSDK.delectScrip())
    }
    
    private func setTimeout(_ result: @escaping FlutterResult, arguments: [String: Any]) {
        TXLoginOauthSDK.setTimeoutInterval(arguments["duration"] as! Double)
        result(nil)
    }
    
    private func dismissLogin(_ result: @escaping FlutterResult, arguments: [String: Any]) {
        TXLoginOauthSDK.dismissViewController(animated: arguments["animated"] as! Bool) {
            result(nil)
        }
    }
}

extension FlutterViewController: UAFSDKLoginDelegate {
    public func authRequestWillStart(_ loginEvent: @escaping UAFContinueLoginEvent) {
        if PrivacyDialog.instance.checked {
            loginEvent(true)
            return
        }
        let root = TverifyPlugin.root
        if let current = root?.presentedViewController ?? root {
            PrivacyDialog.instance.loginEvent = loginEvent
            current.present(PrivacyDialog.instance, animated: true)
        } else {
            PrivacyDialog.instance.loginEvent = nil
            loginEvent(true)
        }
    }
    
    public func authViewPrivacyCheckboxStateToggled(_ checked: Bool) {
        PrivacyDialog.instance.checked = checked
    }
}

private class PrivacyDialog: UIViewController, UAFSDKLoginDelegate {
    static let instance = PrivacyDialog()
    
    fileprivate var loginEvent: ((Bool) -> Void)? = nil
    fileprivate var model: TXLoginUIModel! = nil
    fileprivate lazy var checked: Bool = false
    
    lazy private var rootView: UIView = {
        let root = UIView()
        root.backgroundColor = .white
        return root
    }()
    lazy private var closeButton: UIButton = {
        let close = UIButton.init(type: .custom)
        close.setImage(UIImage(innerName: "windowclose.png"), for: .normal)
        close.contentMode = .scaleToFill
        close.contentEdgeInsets = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12)
        close.addTarget(self, action: #selector(onClose), for: .touchUpInside)
        return close
    }()
    lazy var titleText: UIView = {
        let title = UILabel()
        title.text = "请阅读并同意以下条款"
        title.font = .systemFont(ofSize: 17, weight: .heavy)
        title.textColor = .init(hex: 0xff222222)
        return title
    }()
    lazy private var privacyText: YYLabel = {
        let simInfo = TXLoginOauthSDK.getSimInfo()
        let carrierName: String
        if let rawValue = simInfo["carrier"] as? Int, let carrier = Carrier(rawValue: rawValue) {
            carrierName = carrier.label
        } else {
            carrierName = ""
        }
        let names = model.appPrivacy.map { s in s.string }
        let text = "我已阅读并同意\(names.joined(separator: "、"))\(names.isEmpty ? "" : "和")《中国\(carrierName)帐号服务条款》"
        
        let attributedString = NSMutableAttributedString(string: text)
        let font: UIFont = UIFont.systemFont(ofSize: 13, weight: .medium)
        let color: UIColor = .init(hex: 0xff222222)
        let range: NSRange = .init(location: 0, length: attributedString.length)
        attributedString.addAttribute(.font, value: font, range: range)
        attributedString.addAttribute(.font, value: font, range: range)
        attributedString.addAttribute(.foregroundColor, value: color, range: range)
        var links = [String: String]()
        for string in model.appPrivacy {
            let range = attributedString.mutableString.range(of: string.string)
            let attributes = string.attributes(at: 0, effectiveRange: nil)
            let linkColor = attributes[.foregroundColor] as? UIColor ?? UIColor.init(hex: 0xff3456E6)
            attributedString.addAttributes(attributes, range: range)
            attributedString.yy_setTextHighlight(range, color: linkColor, backgroundColor: nil, userInfo: nil)
            if let link = attributes[.link] as? String {
                links[string.string] = link
            }
        }
        
        attributedString.yy_lineSpacing = 3
        
        let privacyText = YYLabel()
        privacyText.numberOfLines = 0
        privacyText.attributedText = attributedString
        
        privacyText.highlightTapAction = { [weak self] (view, text, range, rect) in
            let substring = text.attributedSubstring(from: range).string
            if let link = links[substring] {
                let safari = SFSafariViewController(url: URL(string: link)!)
                self?.present(safari, animated: true, completion: nil)
            }
        }
        return privacyText
    }()
    lazy private var agreementButton: UIButton = {
        let agreement = UIButton.init(type: .custom)
        agreement.titleLabel?.font = .systemFont(ofSize: 17, weight: .medium)
        agreement.setTitle("同意并继续", for: .normal)
        agreement.setTitleColor(.white, for: .normal)
        agreement.layer.cornerRadius = 7
        agreement.clipsToBounds = true
        agreement.addTarget(self, action: #selector(onAgreement), for: .touchUpInside)
        if let value = model.loginBtnImgs as? [UIImage] {
            agreement.setBackgroundImage(value[0], for: .normal)
            agreement.setBackgroundImage(value[1], for: .disabled)
            agreement.setBackgroundImage(value[2], for: .highlighted)
        } else {
            agreement.setBackgroundImage(UIImage(color: .init(hex: 0xFF5F7CF8)), for: .normal)
            agreement.setBackgroundImage(UIImage(color: .init(hex: 0xAA5F7CF8)), for: .highlighted)
        }
        return agreement
    }()
    
    private init() {
        super.init(nibName: nil, bundle: nil)
        self.modalPresentationStyle = .overFullScreen
        self.modalTransitionStyle = .crossDissolve
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if !animated {
            return
        }
        self.rootView.transform = CGAffineTransformMakeTranslation(0.0, 207)
        UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut]) {
            self.rootView.transform = CGAffineTransformMakeTranslation(0.0, 0.0)
        }
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if !animated {
            return
        }
        UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut]) {
            self.rootView.transform = CGAffineTransformMakeTranslation(0.0, 207)
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black.withAlphaComponent(33.0 / 0xFF)
        
        let touchView = UIView()
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onClose))
        tapGesture.numberOfTapsRequired = 1
        tapGesture.numberOfTouchesRequired = 1
        touchView.addGestureRecognizer(tapGesture)
        view.addSubview(touchView)
        touchView.snp.makeConstraints { make in
            make.width.height.equalToSuperview()
        }
        
        view.addSubview(rootView)
        rootView.snp.makeConstraints { make in
            make.left.bottom.right.equalToSuperview()
        }
        
        // 关闭按钮
        rootView.addSubview(closeButton)
        closeButton.snp.makeConstraints { make in
            make.top.right.equalToSuperview()
            make.width.height.equalTo(40)
        }
        
        // title
        rootView.addSubview(titleText)
        titleText.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(34.5)
            make.centerX.equalToSuperview()
        }
        
        // 隐私协议
        rootView.addSubview(privacyText)
        privacyText.snp.makeConstraints { make in
            make.top.equalTo(titleText.snp.bottom).offset(30)
            make.centerX.equalToSuperview()
            make.width.lessThanOrEqualToSuperview().multipliedBy(343.0 / 375)
        }
        
        // 同意按钮
        rootView.addSubview(agreementButton)
        agreementButton.snp.makeConstraints { make in
            make.top.equalTo(privacyText.snp.bottom).offset(34)
            make.left.equalToSuperview().offset(16)
            make.right.equalToSuperview().offset(-16)
            make.bottom.equalToSuperview().offset(-16)
            make.height.equalTo(45)
        }
    }
    
    @objc private func onClose() {
        self.dismiss(animated: true)
        if let loginEvent = loginEvent {
            loginEvent(false)
        }
    }
    
    @objc private func onAgreement() {
        self.dismiss(animated: true)
        if let loginEvent = loginEvent {
            loginEvent(true)
        }
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        privacyText.preferredMaxLayoutWidth = rootView.bounds.width - 32
        view.layoutIfNeeded()
    }
    
    override func viewSafeAreaInsetsDidChange() {
        super.viewSafeAreaInsetsDidChange()
        let safeArea = view.safeAreaInsets
        closeButton.snp.updateConstraints { make in
            make.right.equalToSuperview().offset(-safeArea.right)
        }
        agreementButton.snp.updateConstraints { make in
            make.left.equalToSuperview().offset(16 + safeArea.left)
            make.right.equalToSuperview().offset(-16 - safeArea.right)
            make.bottom.equalToSuperview().offset(-safeArea.bottom - 16)
        }
        privacyText.preferredMaxLayoutWidth = rootView.bounds.width - safeArea.left - safeArea.right - 32
    }
}

public func loadAsset(_ name: String, package: String? = nil) -> String {
    if let package = package {
        return TverifyPlugin.root.lookupKey(forAsset: name, fromPackage: package)
    } else {
        return TverifyPlugin.root.lookupKey(forAsset: name)
    }
}

private enum Carrier : Int {
    case mobile = 1,
         unicom = 2,
         telecom = 3;
    
    var label: String {
        get {
            switch self {
            case .mobile:
                return "移动"
            case .unicom:
                return "联通"
            case .telecom:
                return "电信天翼"
            }
        }
    }
}
